'    Copyright 2008 Jan Molnar <jan.molnar@abds.de>
'
'    This file is part of JCQ.

'    JCQ is free software: you can redistribute it and/or modify
'    it under the terms of the GNU General Public License as published by
'    the Free Software Foundation, either version 2 of the License, or
'    (at your option) any later version.

'    JCQ is distributed in the hope that it will be useful,
'    but WITHOUT ANY WARRANTY; without even the implied warranty of
'    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'    GNU General Public License for more details.

'    You should have received a copy of the GNU General Public License
'    along with JCQ. If not, see <http://www.gnu.org/licenses/>.

Public MustInherit Class Tlv
    Implements ISerializable

    Private _DataSize As Integer
    Private _TypeNumber As Integer
    Private _HasData As Boolean = False

    Public Const SizeFixPart As Integer = 4

    Public Sub New(ByVal typeNumber As Integer)
        _TypeNumber = typeNumber
    End Sub

    Public Sub New(ByVal typeNumber As Integer, ByVal dataSize As Integer)
        Me.New(typeNumber)

        _DataSize = dataSize
    End Sub

    Public Property TypeNumber() As Integer
        Get
            Return _TypeNumber
        End Get
        Set(ByVal value As Integer)
            _TypeNumber = value
        End Set
    End Property

    Public ReadOnly Property HasData() As Boolean Implements ISerializable.HasData
        Get
            Return _HasData
        End Get
    End Property

    Public Overridable ReadOnly Property DataSize() As Integer Implements ISerializable.DataSize
        Get
            Return _DataSize
        End Get
    End Property

    Public MustOverride Function CalculateDataSize() As Integer Implements ISerializable.CalculateDataSize

    Public ReadOnly Property TotalSize() As Integer Implements ISerializable.TotalSize
        Get
            Return Tlv.SizeFixPart + DataSize
        End Get
    End Property

    Public Function CalculateTotalSize() As Integer Implements ISerializable.CalculateTotalSize
        Return Tlv.SizeFixPart + CalculateDataSize()
    End Function

    Public Overridable Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte)) Implements ISerializable.Deserialize
        _TypeNumber = ByteConverter.ToUInt16(data.GetRange(0, 2))
        _DataSize = ByteConverter.ToUInt16(data.GetRange(2, 2))

        _HasData = True
    End Sub

    Protected Sub SetDataSize(ByVal value As Integer)
        _DataSize = value
        _HasData = True
    End Sub

    Public Overridable Function Serialize() As System.Collections.Generic.List(Of Byte) Implements ISerializable.Serialize
        Dim data As List(Of Byte)

        _DataSize = CalculateDataSize()

        data = New List(Of Byte)(SizeFixPart + _DataSize)

        data.AddRange(ByteConverter.GetBytes(Convert.ToUInt16(TypeNumber)))
        data.AddRange(ByteConverter.GetBytes(Convert.ToUInt16(DataSize)))

        Return data
    End Function

End Class

Public MustInherit Class LETlv
    Inherits Tlv

    Public Sub New(ByVal typeNumber As Integer)
        MyBase.New(typeNumber)
    End Sub

    Public Overrides Sub Deserialize(ByVal data As System.Collections.Generic.List(Of Byte))
        TypeNumber = ByteConverter.ToUInt16LE(data.GetRange(0, 2))
        SetDataSize(ByteConverter.ToUInt16LE(data.GetRange(2, 2)))
    End Sub

    Public Overrides Function Serialize() As System.Collections.Generic.List(Of Byte)
        Dim data As List(Of Byte)

        data = New List(Of Byte)(CalculateTotalSize)

        data.AddRange(ByteConverter.GetBytesLE(Convert.ToUInt16(TypeNumber)))
        data.AddRange(ByteConverter.GetBytesLE(Convert.ToUInt16(CalculateDataSize())))

        Return data
    End Function

End Class

Public Class TlvDescriptor
    Private Sub New(ByVal typeId As Integer, ByVal dataSize As Integer)
        _TypeId = typeId
        _DataSize = dataSize
    End Sub

    Private _TypeId As Integer
    Public ReadOnly Property TypeId() As Integer
        Get
            Return _TypeId
        End Get
    End Property

    Private _DataSize As Integer
    Public ReadOnly Property DataSize() As Integer
        Get
            Return _DataSize
        End Get
    End Property

    Public ReadOnly Property TotalSize() As Integer
        Get
            Return DataSize + 4
        End Get
    End Property

    Public Shared Function GetDescriptor(ByVal offset As Integer, ByVal data As List(Of Byte)) As TlvDescriptor
        Dim typeId As Integer
        Dim dataSize As Integer

        If offset + 4 > data.Count Then
            If Debugger.IsAttached Then Debugger.Break()
            Throw New ArgumentException(String.Format("Offset and length were out of bounds for the present data: {0}/{1}", offset + 4, data.Count))
        End If

        typeId = ByteConverter.ToUInt16(data.GetRange(offset, 2))
        dataSize = ByteConverter.ToUInt16(data.GetRange(offset + 2, 2))

        Return New TlvDescriptor(typeId, dataSize)
    End Function
End Class

'Public Class UnknownTlv
'    Inherits Tlv



'    public Overrides Function CalculateDataSize() As Integer
'        Throw New NotImplementedException
'    End Function
'End Class